#!/usr/bin/env bash
# UOS-V20_1050u1e-aarch64
# 1) 系统补丁 -> 最新（容错：跳过/禁用不可用仓库）
# 2) OpenSSL 3.5.2（共享库）
# 3) OpenSSH（默认 10.0p2，自动处理 libfido2 缺包）
# 4) SSH 端口蓝绿切换到 20000–40000 随机可用端口（放行防火墙/SELinux）
# 5) 修复 systemd 单元变量导致的 sshd 启动失败
# 6) 输出最终版本与端口
set -euo pipefail

OPENSSH_VER="${1:-10.0p2}"
OPENSSL_VER="3.5.2"
OPENSSH_URL="https://mirrors.aliyun.com/pub/OpenBSD/OpenSSH/portable/openssh-${OPENSSH_VER}.tar.gz"
OPENSSL_URL="https://mirrors.aliyun.com/macports/distfiles/openssl3/openssl-${OPENSSL_VER}.tar.gz"

PREFIX_OPENSSL="/usr/local/openssl-${OPENSSL_VER}"
OPENSSL_LINK="/usr/local/openssl"
BUILD_DIR="/usr/local/src"
BACKUP_DIR="/usr/local/backup-ssh-$(date +%Y%m%d%H%M%S)"
MAKE_JOBS="${MAKE_JOBS:-$(nproc)}"

info(){ echo -e "\033[1;34m[INFO]\033[0m $*" >&2; }
warn(){ echo -e "\033[1;33m[WARN]\033[0m $*" >&2; }
err(){  echo -e "\033[1;31m[ERR ]\033[0m $*" >&2; }

need_root(){ [ "$(id -u)" -eq 0 ] || { err "请用 root 运行"; exit 1; }; }

detect_pkg(){
  if command -v apt >/dev/null 2>&1; then PKG="apt"
  elif command -v dnf >/dev/null 2>&1; then PKG="dnf"
  elif command -v yum >/dev/null 2>&1; then PKG="yum"
  else err "未找到 apt/dnf/yum"; exit 1; fi
  info "包管理器：$PKG"
}

# --- 容错系统更新：跳过不可用仓库；必要时临时禁用失败仓库再继续 ---
update_system(){
  info "开始更新系统补丁到最新……"
  case "$PKG" in
    apt)
      export DEBIAN_FRONTEND=noninteractive
      apt update || warn "apt update 失败，将尝试继续其余步骤"
      apt -y full-upgrade || warn "APT 升级失败，已跳过系统补丁更新"
      apt -y autoremove --purge || true
      ;;
    dnf)
      # 先尝试正常刷新/升级，容忍不可用仓库
      dnf -y --setopt=skip_if_unavailable=True --refresh makecache || warn "dnf makecache 失败（跳过不可用仓库）"
      if ! dnf -y --setopt=skip_if_unavailable=True --refresh upgrade; then
        warn "dnf upgrade 失败，将尝试解析并临时禁用出错仓库后重试"
        # 解析报错行：Errors during downloading metadata for repository 'REPOID':
        local bad_repos dis=""
        bad_repos="$(dnf -v -y --refresh makecache 2>&1 | sed -n "s/.*repository '\([^']*\)'.*/\1/p" | sort -u | xargs || true)"
        if [ -n "$bad_repos" ]; then
          for r in $bad_repos; do warn "临时禁用仓库：$r"; dis="$dis --disablerepo=$r"; done
          dnf -y --refresh upgrade $dis || warn "禁用失败仓库后仍无法升级，本次跳过系统补丁更新"
        else
          warn "未识别到具体失败仓库，本次跳过系统补丁更新"
        fi
      fi
      ;;
    yum)
      yum -y --setopt=skip_if_unavailable=True makecache || warn "yum makecache 失败（跳过不可用仓库）"
      yum -y --setopt=skip_if_unavailable=True update || warn "YUM 升级失败，已跳过系统补丁更新"
      ;;
  esac
  info "系统补丁步骤完成（如有 WARN，可忽略并继续后续升级）。"
}

# --- 依赖安装（缺包自动跳过；解决 fido2-devel 不存在）---
install_try(){
  case "$PKG" in
    apt)
      local to_install=()
      for p in "$@"; do apt-cache show "$p" >/dev/null 2>&1 && to_install+=("$p"); done
      [ "${#to_install[@]}" -gt 0 ] && apt -y install "${to_install[@]}" || true
      ;;
    dnf|yum)
      local mgr="$PKG"; local to_install=()
      for p in "$@"; do
        if "$mgr" list --available "$p" >/dev/null 2>&1 || "$mgr" list installed "$p" >/dev/null 2>&1; then
          to_install+=("$p")
        fi
      done
      [ "${#to_install[@]}" -gt 0 ] && "$mgr" -y install "${to_install[@]}" || true
      ;;
  esac
}

install_build_deps(){
  info "安装编译依赖（缺包自动跳过）……"
  case "$PKG" in
    apt)
      export DEBIAN_FRONTEND=noninteractive
      install_try build-essential wget curl ca-certificates tar pkg-config \
        zlib1g-dev libpam0g-dev libselinux1-dev libedit-dev \
        libfido2-dev libcbor-dev autoconf automake libtool
      ;;
    dnf|yum)
      install_try gcc gcc-c++ make wget curl ca-certificates tar pkgconfig \
        zlib-devel pam-devel libselinux-devel libedit-devel \
        libfido2-devel libcbor-devel autoconf automake libtool openssl-devel
      ;;
  esac
}

prepare_build_env(){ mkdir -p "$BUILD_DIR" "$BACKUP_DIR"; cd "$BUILD_DIR"; }

download_and_extract(){
  local url="$1"; local out="$2"
  info "下载: $url"
  (curl -fsSL "$url" -o "$out" || wget -O "$out" "$url") 2>&1 >&2
  local topdir; topdir="$(tar tzf "$out" | head -1 | cut -d/ -f1)"
  [ -n "$topdir" ] || { err "无法解析 tar 包目录结构"; exit 1; }
  rm -rf "$topdir"; tar xzf "$out"; printf '%s' "$topdir"
}

build_openssl(){
  info "构建 OpenSSL ${OPENSSL_VER}……"
  local tarball="openssl-${OPENSSL_VER}.tar.gz"
  local srcdir; srcdir="$(download_and_extract "$OPENSSL_URL" "$tarball")"
  cd "$srcdir"
  ./config --prefix="${PREFIX_OPENSSL}" --openssldir="${PREFIX_OPENSSL}/ssl" zlib || \
  ./Configure linux-generic64 --prefix="${PREFIX_OPENSSL}" --openssldir
